package tr.richfacesext.components.chart;

import java.awt.Font;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.eastwood.ChartEngine;
import org.jfree.eastwood.Parameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import tr.richfacesext.components.ComponentConstants;

/**
 * 
 * @author mert
 *
 */
@SuppressWarnings("serial")
public class EastwoodChartServingPhaseListener implements PhaseListener {

	private final Logger logger = LoggerFactory.getLogger(getClass());
	
	public void beforePhase(PhaseEvent event) {
		//No-op
	}
	
	public void afterPhase(PhaseEvent event) {
		FacesContext context = event.getFacesContext();
		String viewRootId = context.getViewRoot().getViewId();
		
		if (viewRootContainsPLKey(ComponentConstants.RICHFACESEXT_CHART_VIEW_ID, viewRootId)) {
			try {
				serveChart(context, viewRootId, fontSize());
			} 
			catch (IOException e) {
				logger.error("Error occured while rendering chart", e);
			}
		}
	}

	private Font fontSize() {
        float fontSize = 12f;		
        return new Font("Dialog", Font.PLAIN, (int) fontSize);
	}

	private void serveChart(FacesContext context, String viewRootId, Font font) throws IOException {
		HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
		HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
		
	    OutputStream out = response.getOutputStream();

	    System.out.println(request.getQueryString());
	    
        try {
            Map params = Parameters.parseQueryString(request.getQueryString());
            JFreeChart chart = ChartEngine.buildChart(params, font);

            if (chart != null) {
                response.setContentType("image/png");

                String[] size = (String[]) params.get("chs");
                int[] dims = new int[2];
                if (size != null) {
                    dims = parseChartDimensions(size[0]);
                }
                else {
                    dims = new int[] {200, 125};
                }

                ChartUtilities.writeChartAsPNG(out, chart, dims[0], dims[1]);
    			out.flush();
    			context.responseComplete();    			
            }
        }
        catch (Exception e) {
        	logger.error("Exception occured while serving chart", e);
        }
        finally {
            out.close();
        }
	}

	public PhaseId getPhaseId() {
		return PhaseId.RESTORE_VIEW;
	}
	
	private boolean viewRootContainsPLKey(String viewId, String viewRootId) {
		return viewRootId.startsWith(viewId) || viewRootId.startsWith("/" + viewId);
	}	
	
   private int[] parseChartDimensions(String text) throws Exception {
        if (text == null) {
            throw new IllegalArgumentException("Null 'text' argument (in parseChartDimensions(String)).");
        }
        int[] result = new int[2];
        int splitIndex = text.indexOf('x');
        String xStr = text.substring(0, splitIndex);
        String yStr = text.substring(splitIndex + 1);
        int x = Integer.parseInt(xStr);
        int y = Integer.parseInt(yStr);
        if (x <= 1000 && y <= 1000 && x * y < 360000) {
            result[0] = x; result[1] = y;
        }
        else {
            throw new Exception("Invalid chart dimensions: " + xStr + ", " + yStr);
        }
        return result;
    }
}